﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using System.Xml;

namespace InkFx.WinControl.Utils
{
    public static class ImageHelper
    {

        #region  基 本 操 作

        /// <summary>
        /// 通过文件路径创建System.Drawing.Image
        /// </summary>
        public static System.Drawing.Image GetImageFromFile(string file)
        {
            try
            {
                file = FileHelper.FormatFullPath(file);
                if (!FileHelper.ExistFile(file)) return null;

                using (Image image = Image.FromFile(file))
                {
                    Bitmap bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
                    using (Graphics g = Graphics.FromImage(bitmap))
                        g.DrawImage(image, new Rectangle(0, 0, bitmap.Width, bitmap.Height), new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);

                    //SaveImage(bitmap, @"D:\AAAAAXXX.png");
                    return bitmap;
                }
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) { Tools.LogWarn2(ex, "将文件读取为图片错误"); return null; }
        }
        /// <summary>
        /// 通过图片获取图片的字节 (编码格式为 png)
        /// </summary> 
        public static byte[] GetImageBytes(System.Drawing.Image image)
        {
            if (image == null) return null;
            try
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    //if (image.RawFormat == ImageFormat.Bmp || image.RawFormat == ImageFormat.Emf || image.RawFormat == ImageFormat.Exif || image.RawFormat == ImageFormat.Gif || image.RawFormat == ImageFormat.Icon || image.RawFormat == ImageFormat.Jpeg || image.RawFormat == ImageFormat.MemoryBmp || image.RawFormat == ImageFormat.Png || image.RawFormat == ImageFormat.Tiff || image.RawFormat == ImageFormat.Wmf)
                    //    image.Save(mstream, image.RawFormat);
                    //else
                    image.Save(stream, ImageFormat.Png);
                    return stream.ToArray();
                }
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) { Tools.LogWarn2(ex, "将图片转换为字节错误"); return null; }
        }
        /// <summary>
        /// 通过图片获取图片的字节 (编码格式为 gif)
        /// </summary> 
        public static byte[] GetGifImageBytes(System.Drawing.Image image)
        {
            if (image == null) return null;
            try
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    //if (image.RawFormat == ImageFormat.Bmp || image.RawFormat == ImageFormat.Emf || image.RawFormat == ImageFormat.Exif || image.RawFormat == ImageFormat.Gif || image.RawFormat == ImageFormat.Icon || image.RawFormat == ImageFormat.Jpeg || image.RawFormat == ImageFormat.MemoryBmp || image.RawFormat == ImageFormat.Png || image.RawFormat == ImageFormat.Tiff || image.RawFormat == ImageFormat.Wmf)
                    //    image.Save(mstream, image.RawFormat);
                    //else
                    image.Save(stream, ImageFormat.Gif);
                    return stream.ToArray();
                }
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) { Tools.LogWarn2(ex, "将图片转换为字节错误"); return null; }
        }
        /// <summary>
        /// 将字节流转换成System.Drawing.Image
        /// </summary>
        public static System.Drawing.Image GetImageFromBytes(byte[] bytes)
        {
            if (bytes == null || bytes.Length <= 0) return null;
            try
            {
                //创建图片的流 不允许释放, 否则将导致 使用GIF图片时 出现错误: GDI+ 中发生一般性错误。
                //using (MemoryStream ms = new MemoryStream(bytes))
                //    return System.Drawing.Image.FromStream(ms);

                MemoryStream ms = new MemoryStream(bytes);
                return System.Drawing.Image.FromStream(ms);
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) { Tools.LogWarn2(ex, "将字节读取为图片错误"); return null; }
        }
        /// <summary>
        /// 将一个 Base64 字符串转换成 System.Drawing.Image
        /// </summary>
        public static System.Drawing.Image GetImageFromBase64(string base64)
        {
            if (Tools.IsNullOrWhiteSpace(base64)) return null;
            try
            {
                byte[] bytes = Convert.FromBase64String(base64);
                System.Drawing.Image image = GetImageFromBytes(bytes);
                return image;
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) { Tools.LogWarn2(ex, "将base64读取为图片错误"); return null; }
        }
        /// <summary>
        /// 将一个 System.Drawing.Image 转传承 Base64
        /// </summary>
        public static string GetImageBase64(System.Drawing.Image image)
        {
            if (image == null) return string.Empty;
            try
            {
                byte[] bytes = GetImageBytes(image);
                string base64 = Convert.ToBase64String(bytes);
                return base64;
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) { Tools.LogWarn2(ex, "将图片转换为base64错误"); return string.Empty; }
        }
        /// <summary>
        /// 克隆一张图片数据
        /// </summary>
        public static System.Drawing.Image CloneImage(System.Drawing.Image source)
        {
            if (source == null) return null;

            try
            {
                byte[] bytes = GetImageBytes(source);
                return GetImageFromBytes(bytes);
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) { Tools.LogWarn2(ex, "执行图片克隆错误"); return null; }
        }

        /// <summary>
        /// 保存图片
        /// </summary>
        public static bool SaveImage(System.Drawing.Image sourceImage, string imagePath)
        {
            return SaveImage(sourceImage, imagePath, 100, false);
        }
        private static bool SaveImage(System.Drawing.Image sourceImage, string imagePath, long quality, bool throwException)
        {
            if (sourceImage == null) return false;

            imagePath = FileHelper.FormatFullPath(imagePath);
            FileHelper.CreateFolder(imagePath);

            try
            {
                ////直接保存，得到的图片 字节将会 特别多
                //sourceImage.Save(imagePath); 

                ////指定格式保存，得到的图片 字节流很少 但是质量太差
                //string extension = (Path.GetExtension(imagePath) + string.Empty).ToLower().Trim();
                //if (extension == ".jpg" || extension == ".jpeg")
                //    sourceImage.Save(imagePath, ImageFormat.Jpeg);
                //if (extension == ".gif")
                //    sourceImage.Save(imagePath, ImageFormat.Gif);
                //if (extension == ".png")
                //    sourceImage.Save(imagePath, ImageFormat.Png);
                //if (extension == ".bmp")
                //    sourceImage.Save(imagePath, ImageFormat.Bmp);
                //if (extension == ".tiff")
                //    sourceImage.Save(imagePath, ImageFormat.Tiff);
                //#if (!WindowsCE && !PocketPC)
                //if (extension == ".ico")
                //    sourceImage.Save(imagePath, ImageFormat.Icon);
                //#endif

                //指定精度，得到的图片 字节流比原画多 质量比格式化保存好很多
                EncoderParameter encoderParameter = new EncoderParameter(Encoder.Quality, quality);
                EncoderParameters encoderParameters = new EncoderParameters(1);
                encoderParameters.Param[0] = encoderParameter;

                string extension = (Path.GetExtension(imagePath) + string.Empty).ToLower().Trim();
                if (extension == ".jpg" || extension == ".jpeg")
                    sourceImage.Save(imagePath, GetImageCodecInfo(ImageFormat.Jpeg), encoderParameters);
                else if (extension == ".gif")
                    sourceImage.Save(imagePath, GetImageCodecInfo(ImageFormat.Gif), encoderParameters);
                else if (extension == ".png")
                    sourceImage.Save(imagePath, GetImageCodecInfo(ImageFormat.Png), encoderParameters);
                else if (extension == ".bmp")
                    sourceImage.Save(imagePath, GetImageCodecInfo(ImageFormat.Bmp), encoderParameters);
                else if (extension == ".tiff")
                    sourceImage.Save(imagePath, GetImageCodecInfo(ImageFormat.Tiff), encoderParameters);
                else if (extension == ".ico")
                    sourceImage.Save(imagePath, ImageFormat.Icon);
                else
                    sourceImage.Save(imagePath + ".png", GetImageCodecInfo(ImageFormat.Png), encoderParameters);

                return true;
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) 
            {
                if (throwException) throw;
                Tools.LogWarn2(ex, "保存图片为磁盘文件错误");
                return false;
            }
        }

        public static ImageCodecInfo GetImageCodecInfo(string mimeType)
        {
            ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
            for (int i = 0; i < encoders.Length; ++i)
            {
                if (string.Equals(encoders[i].MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase))
                    return encoders[i];
            }
            return null;
        }
        public static ImageCodecInfo GetImageCodecInfo(ImageFormat imageFormat)
        {
            string mimeType = string.Empty;
            if (Equals(imageFormat, ImageFormat.Jpeg)) mimeType = "image/jpeg";
            else if (Equals(imageFormat, ImageFormat.Gif)) mimeType = "image/gif";
            else if (Equals(imageFormat, ImageFormat.Tiff)) mimeType = "image/tiff";
            else if (Equals(imageFormat, ImageFormat.Png)) mimeType = "image/png";
            else if (Equals(imageFormat, ImageFormat.Bmp)) mimeType = "image/bmp";

            ImageCodecInfo imageCodecInfo = GetImageCodecInfo(mimeType);
            return imageCodecInfo;
        }

        /// <summary>
        /// 判断某个图片路径是否是 图片文件
        /// </summary>
        public static bool IsImageByFileName(string fileName)
        {
            if (string.IsNullOrEmpty(fileName)) return false;
            string extension = Path.GetExtension(fileName);
            if (string.IsNullOrEmpty(extension)) return false;
            extension = extension.ToLower().Trim();
            if (extension == ".jpg" || extension == ".jpeg" || extension == ".gif" || extension == ".bmp" || extension == ".png")
                return true;
            return false;
        }

        #endregion


        #region  其 他 操 作


        private static readonly Hash<Image> m_HashFileIcon = new Hash<Image>();
        
        /// <summary>
        /// 获取指定文件路径或者文件名 对应的 文件图标
        /// </summary>
        /// <param name="path">文件路径或者文件名</param>
        public static Image GetFileIcon(string path)
        {
            try
            {
                bool folder = path.EndsWith("\\") || path.EndsWith("/") || Directory.Exists(path);
                string extension = folder ? "Folder" : (Path.GetExtension(path) ?? "").Replace(".", "").ToLower();
                if (string.IsNullOrEmpty(extension)) return null;
                var image = m_HashFileIcon[extension];
                if (image != null) return image;

                if (folder)
                {
                    const string base64 = @"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAYNJREFUeNqMUz1LA0EQnf04MCIIgiIiKhKsbfwTdtZaioWN2Kgglv6ANFaWClaxEfFPiKmDxMRCJJLGnGeSm911Zi/xUtwlWRh2b2fe2/dm90S1JIGHELBL0wpMNt6dg1teaNffoY3Vjf37SzBmNFQpqF7vnA8+tXX/KQkYg4vjkXgRBEAYmRLYlMDS6W6MAiElECYlMCmBchMQABEQRmURSAZbg2PwniBbgTUxGBzTA629gkHvNA4TICnAfAW6MA1f9QZgYmGTbq4iWUE/qAfoLWSFpOtrvjVIoYGtMzyh+j1WodEMK4jB5liw5D1qt2G5uAZRrweEUxkWkE7AnOYpemOJxbDTGdigJg4r8HJzFBgFiImdn26XH6wnkC91YDYOnVxjdnDO9OeD+ryvZ5w8vbHwXBPw2xNTziYFmUG5DknnudWKfD3j+EEULu7MwncEM1JICHSQGZwLw9DPxw+z5aeKKxOuIIhgjmLpaFsdFhdhfZJ/+fUTaqVHc0XLjz8BBgAe8hnM7R7yAAAAAABJRU5ErkJggg==";
                    image = GetImageFromBase64(base64);
                    if (image != null) { m_HashFileIcon[extension] = image; }
                }
                else
                {
                    //这段代码虽然简单, 却只能获取 32x32 的图标
                    //var icon = Icon.ExtractAssociatedIcon(path);
                    //image = icon == null ? null : icon.ToBitmap();
                    //if (icon != null) { m_HashFileIcon[extension] = image; }

                    const uint SHGFI_ICON = 0x100;
                    const uint SHGFI_LARGEICON = 0x0; //32x32
                    const uint SHGFI_SMALLICON = 0x1; //16x16
                    const uint SHGFI_USEFILEATTRIBUTES = 0x10;
                    SHFILEINFO info = new SHFILEINFO();
                    int result = SHGetFileInfo(path, 0, ref info, 0, SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON);//从文件扩展名得到小图标
                    image = (result > 0) ? Icon.FromHandle(info.hIcon).ToBitmap() : null;
                    if (image != null) { m_HashFileIcon[extension] = image; }
                }

                return image;
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex) { Tools.LogWarn2(ex, "获取文件图标错误"); return null; }
        }
        /// <summary>
        /// 获取指定文件路径或者文件名 对应的 文件图标, 并将图标填充到指定的 ImageList 中
        /// <para>如果 相同扩展名的图标已经存在, 则不会再次识别文件图标</para>
        /// </summary>
        /// <returns>返回值是 图标在 imageList 中的 key 值</returns>
        public static string FillFileIconToImageList(ImageList imageList, string path)
        {
            if (imageList == null) return string.Empty;
            bool folder = path.EndsWith("\\") || path.EndsWith("/") || Directory.Exists(path);
            string extension = folder ? "Folder" : (Path.GetExtension(path) ?? "").Replace(".", "").ToLower();
            if (string.IsNullOrEmpty(extension)) return string.Empty;

            var image = imageList.Images[extension];
            if (image != null) return extension;

            var icon = GetFileIcon(path);
            if (icon != null) { imageList.Images.Add(extension, icon); }
            return extension;
        }



        [DllImport("Shell32.dll")]
        private static extern int SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
        private struct SHFILEINFO
        {
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            public char szDisplayName;
            public char szTypeName;
        }


        #endregion


    }



}
